﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Kexp.ShoutcastRunner.Tests
{
	[TestClass]
	public class TestW3CLogParser
	{
		private const string TestLine1 = "11.111.11.111 22.222.22.222 2012-09-05 13:04:09 /stream?title=KEXP%2090%2E3%20FM%20%2D%20Time%3A%2012%3A59%20PM%20Artist%3A%20Frank%20Black%20Song%3A%20%60Hang%20On%20to%20Your%20Ego%60%20Album%3A%20Frank%20Black 200 HTC%20Streaming%20Player%20htc%5Feurope%20%2F%201%2E0%20%2F%20htc%5Fsaga%20%2F%202%2E3%2E5 416316 96 34688";
		private const string TestLine2 = "11.111.11.111 22.222.22.222 2012-09-05 13:05:22 /stream?title=KEXP%2090%2E3%20FM%20%2D%20Time%3A%2012%3A59%20PM%20Artist%3A%20Frank%20Black%20Song%3A%20%60Hang%20On%20to%20Your%20Ego%60%20Album%3A%20Frank%20Black 200 vlc%2F1%2E1%2E11 557056 110 40512";
		private const string TestLine3 = "111.111.111.11 222.222.222.22 2012-10-05 15:27:54 /stream?title=KEXP%2090%2E3%20FM%20%2D%20Time%3A%203%3A26%20PM%20Artist%3A%20Prince%20 200 kexp%2Dradio%2F2%2E0%20CFNetwork%2F609%20Darwin%2F13%2E0%2E0 965 1 7720";

		private const string FieldLine1 = "#Fields: c-ip c-dns date time cs-uri-stem c-status cs(User-Agent) sc-bytes x-duration avgbandwidth";
		private const string FieldLine2 = "   #Fields: c-ip c-dns date time cs-uri-stem c-status cs(User-Agent) sc-bytes x-duration avgbandwidth";

		[TestMethod]
		public void Line_ParsesCorrectly()
		{
			var line = new W3CLogParser.Line(TestLine1);

			Assert.AreEqual("11.111.11.111", line.ClientIp);
			Assert.AreEqual("22.222.22.222", line.ClientDns);
			Assert.AreEqual("2012-09-05", line.DateString);
			Assert.AreEqual("13:04:09", line.TimeString);
			Assert.AreEqual(new DateTime(2012, 9, 5, 13, 4, 9), line.LineDateTime);
			Assert.AreEqual("/stream?title=KEXP%2090%2E3%20FM%20%2D%20Time%3A%2012%3A59%20PM%20Artist%3A%20Frank%20Black%20Song%3A%20%60Hang%20On%20to%20Your%20Ego%60%20Album%3A%20Frank%20Black", line.RequestPath);
			Assert.AreEqual("200", line.RequestStatus);
			Assert.AreEqual("HTC%20Streaming%20Player%20htc%5Feurope%20%2F%201%2E0%20%2F%20htc%5Fsaga%20%2F%202%2E3%2E5", line.UserAgent);
			Assert.AreEqual("416316", line.BytesSent);
			Assert.AreEqual("96", line.Duration);
			Assert.AreEqual("34688", line.AverageBandwidth);
		}

		[TestMethod]
		public void Line_IsFieldLine_WorksCorrectly()
		{
			var line = new W3CLogParser.Line(TestLine3);
			Assert.IsFalse(line.IsFieldLine());

			line = new W3CLogParser.Line(FieldLine1);
			Assert.IsTrue(line.IsFieldLine());

			line = new W3CLogParser.Line(FieldLine2);
			Assert.IsTrue(line.IsFieldLine());
		}

		[TestMethod]
		public void Line_IsComment_WorksCorrectly()
		{
			var line = new W3CLogParser.Line("#blah");
			Assert.IsTrue(line.IsComment());

			line = new W3CLogParser.Line(FieldLine2);
			Assert.IsTrue(line.IsComment());
		}

		[TestMethod]
		public void Line_GetDate_WorksCorrectly()
		{
			var line = new W3CLogParser.Line(FieldLine1);
			Assert.IsNull(line.LineDateTime);

			line = new W3CLogParser.Line(TestLine3);
			Assert.AreEqual(new DateTime(2012, 10, 5, 15, 27, 54), line.LineDateTime);

			// 2012-09-05 13:04:09
			line = new W3CLogParser.Line(TestLine2);
			Assert.AreEqual(new DateTime(2012, 9, 5, 13, 5, 22), line.LineDateTime);
		}

		[TestMethod]
		public void Line_ToString_TruncatingRequestPath_WorksCorrectly()
		{
			var line = new W3CLogParser.Line(FieldLine1);
			Assert.AreEqual(FieldLine1, line.ToString(true));

			line = new W3CLogParser.Line(TestLine3);
			Assert.AreEqual("111.111.111.11 222.222.222.22 2012-10-05 15:27:54 /stream?title=Unknown 200 kexp%2Dradio%2F2%2E0%20CFNetwork%2F609%20Darwin%2F13%2E0%2E0 965 1 7720", line.ToString(true));

			// 2012-09-05 13:04:09
			line = new W3CLogParser.Line(TestLine2);
			Assert.AreEqual("11.111.11.111 22.222.22.222 2012-09-05 13:05:22 /stream?title=Unknown 200 vlc%2F1%2E1%2E11 557056 110 40512", line.ToString(true));
		}

		[TestMethod]
		//[Ignore] // you'll probably want to modify the testfile below
		public void ParseDailyLogs_GivenRegularLog_ReturnsFalse()
		{
			string testFile = @"c:\test\shoutcast\sc_serv.log";
			Assert.IsFalse(W3CLogParser.ParseDailyLogs(testFile, 50000));
		}

		[TestMethod]
		[Ignore] // you'll probably want to modify the testfile below
		public void ParseDailyLogs_GivenW3CLog_WorksAsExpected()
		{
			string testFile = @"c:\test\shoutcast\sc_w3c.log";
			Assert.IsTrue(W3CLogParser.ParseDailyLogs(testFile, 50000));
		}

		[TestMethod]
		public void Listener_GetPreviousConnectedVisit_WorksAsExpected()
		{
			// the linedate is the "end", subtract duration to get the "start"
		    var listener = new W3CLogParser.Listener();

			var first = new W3CLogParser.Visit {StopDate = new DateTime(2012, 12, 1, 13, 5, 22), Duration = 192, BytesSent = 1048826};
			var second = new W3CLogParser.Visit {StopDate = new DateTime(2012, 12, 1, 13, 5, 22), Duration = 1, BytesSent = 908};
			var third = new W3CLogParser.Visit {StopDate = new DateTime(2012, 12, 1, 13, 6, 22), Duration = 60, BytesSent = 239924};
            var fourth = new W3CLogParser.Visit { StopDate = new DateTime(2012, 12, 1, 13, 8, 22), Duration = 120, BytesSent = 480120};
			var fifth = new W3CLogParser.Visit {StopDate = new DateTime(2012, 12, 1, 13, 8, 22), Duration = 1, BytesSent = 945};
			var sixth = new W3CLogParser.Visit { StopDate = new DateTime(2012, 12, 1, 13, 11, 38), Duration = 195, BytesSent = 780643};
			var seventh = new W3CLogParser.Visit { StopDate = new DateTime(2012, 12, 1, 13, 11, 38), Duration = 1, BytesSent = 938};
			var eighth = new W3CLogParser.Visit { StopDate = new DateTime(2012, 12, 1, 13, 15, 08), Duration = 210, BytesSent = 840817};
			var ninth = new W3CLogParser.Visit { StopDate = new DateTime(2012, 12, 1, 13, 18, 38), Duration = 211, BytesSent = 841256};
			var tenth = new W3CLogParser.Visit { StopDate = new DateTime(2012, 12, 11, 20, 0, 0), Duration = 5, BytesSent = 1001679};

		    long expectedBytes = second.BytesSent + third.BytesSent + fourth.BytesSent + fifth.BytesSent + sixth.BytesSent +
		                         seventh.BytesSent + eighth.BytesSent + ninth.BytesSent;

            listener.AddVisit(second);
            listener.AddVisit(third);

            // these first two visits should be connected into one
            Assert.IsTrue(listener.Visits.Count == 1);
            Assert.AreEqual(third.StopDate, listener.Visits[0].StopDate);
            Assert.AreEqual(61, listener.Visits[0].Duration);
            Assert.AreEqual(240832, listener.Visits[0].BytesSent);

            listener.AddVisit(fourth);
            listener.AddVisit(fifth);
            listener.AddVisit(sixth);
            listener.AddVisit(seventh);
            listener.AddVisit(eighth);
            listener.AddVisit(ninth);

            // should still be one visit
            Assert.AreEqual(1, listener.Visits.Count);
            Assert.AreEqual(ninth.StopDate, listener.Visits[0].StopDate);

		    int expectedDuration = 797; // you'd think 799, but we're being a bit more precise, as sometimes
            // there are entries 1 second long that are not actually adding a second to the duration 
            // by date/time
            Assert.AreEqual(expectedDuration, listener.Visits[0].Duration);
            Assert.AreEqual(expectedBytes, listener.Visits[0].BytesSent);

            // trying to add one in between should create a new visit
            listener.AddVisit(fifth);
            Assert.AreEqual(2, listener.Visits.Count);

            // adding a connected line from the past should prepend? Probably not worth implementing that.
            // for now let's expect it to create a new visit
            listener.AddVisit(first);
            Assert.AreEqual(3, listener.Visits.Count);

            // adding one out of sequence should create a new visit
            listener.AddVisit(tenth);
            Assert.AreEqual(4, listener.Visits.Count);
        }

		[TestMethod]
		//[Ignore] // you'll probably want to modify the testfile below
        public void ParseTritonDailyLogs_GivenW3CLog_WorksAsExpected()
		{
            string testFile = @"c:\test\shoutcast\11\sc_w3c.log";
            Assert.IsTrue(W3CLogParser.ParseTritonDailyLogs(testFile, 50000));

            testFile = @"c:\test\shoutcast\12\sc_w3c.log";
            Assert.IsTrue(W3CLogParser.ParseTritonDailyLogs(testFile, 50000));

            testFile = @"c:\test\shoutcast\13\sc_w3c.log";
            Assert.IsTrue(W3CLogParser.ParseTritonDailyLogs(testFile, 50000));

            testFile = @"c:\test\shoutcast\14\sc_w3c.log";
            Assert.IsTrue(W3CLogParser.ParseTritonDailyLogs(testFile, 50000));
        }
	}
}
